import tornado.escape
import tornado.template
import tornado.web

import logging
import os
import re

from helpers import *


class SettingsMixin(object):
	def get_setting(self, key):
		setting = self.db.get(
			'SELECT value FROM settings WHERE identifier = %s', key)

		try:
			return setting.value
		except:
			logging.error("Couldn't retrieve setting '%s'", key)

	def set_setting(self, id, value):
		try:
			updated_setting = self.db.execute(
				'UPDATE settings SET value = %s WHERE identifier = %s',
				value, id)

			logging.info("Set '%s' to '%s'", id, value)
			return updated_setting
		except:
			logging.error("Couldn't update setting")


class PageMixin(object):
	def get_page(self, slug):
		page = self.db.get(
			'SELECT * FROM pages WHERE slug = %s',
			slug or self.default_page)

		return page

	def save_page(self, **args):
		args['slug'] = slug = slugify(args['name'])
		fields = ', '.join([arg[0] + " = %s" for arg in args.items()])
		values = [arg[1] for arg in args.items()]

		if 'id' in args:
			page_id = int(args['id'])
			values.append(page_id)
			del args['id']

			old_slug = tornado.escape.to_unicode(self.db.get(
				'SELECT slug FROM pages WHERE id = %s ', page_id).slug)

			if old_slug != slug:
				if self.page_exists(slug):
					logging.error("Name '%s' already in use", args['name'])
					return False

				self._set_history(page_id, old_slug)

			self.db.execute(
				'UPDATE pages SET %s WHERE id = %%s' \
				% fields, *values)

			return slug

		if self.page_exists(slug):
			logging.error("Name '%s' already in use", args['name'])
			return False

		self.db.execute(
			'INSERT INTO pages SET %s, created = CURRENT_TIMESTAMP' \
			% fields, *values)

		return slug

	def delete_page(self, page_id):
		base_path = os.path.join(
			self.settings['static_path'], self.settings['upload_path'])

		uploads = self.db.query(
			'SELECT path, preview_path FROM uploads WHERE page_id = %s', page_id)

		for upload in uploads:
			if not remove_uploaded_file(base_path, upload):
				logging.error('Missing file not deleted')

		self.db.execute(
			'DELETE FROM pages WHERE id = %s', page_id)
		self.db.execute(
			'DELETE FROM permalinks WHERE page_id = %s', page_id)
		self.db.execute(
			'DELETE FROM uploads WHERE page_id = %s', page_id)

		return True

	def get_permalink(self, slug):
		permalink = self.db.get(
			'SELECT pages.slug FROM permalinks, pages WHERE '
			'permalinks.page_id = pages.id AND permalinks.slug = %s '
			'ORDER BY permalinks.created DESC LIMIT 1', slug)

		if not permalink:
			return False

		return permalink.slug

	def page_exists(self, slug):
		exists = self.db.get(
			'SELECT id FROM pages WHERE slug = %s',
			 slug)

		if exists or slug in self.settings['reserved_pages']:
			return True

		return False

	def _set_history(self, page_id, slug):
		permalink = self.db.execute(
			'INSERT INTO permalinks SET page_id = %s, slug = %s', page_id, slug)

		return permalink

	@property
	def default_page(self):
		try:
			page = self.db.get(
				'SELECT slug FROM pages WHERE id = %s',
			    self.get_setting('default_page'))

			return page.slug
		except:
			logging.error('Default page not set')


class UploadsMixin(object):
	_SUPPORTED_IMAGE_TYPES = (
		'image/jpeg',
		'image/gif',
		'image/png'
	)

	def upload_files(self, key, origin):
		files = self.request.files[key]

		if not files:
			return False

		increment = self._upload_increment(origin)
		uploads = []

		for file in files:
			original_name = file['filename']
			content_type = file['content_type']
			file['filename'] = self._generate_name(original_name)
			path = write_file(file, self._base_path)
			preview_path = None

			if not path:
				raise tornado.web.HTTPError(500, 'Upload failed')

			if content_type in self._SUPPORTED_IMAGE_TYPES:
				preview_path = create_preview(path, self.settings['upload_preview_size'])

				try:
					preview_path = os.path.basename(preview_path)
				except:
					logging.error("Error creating preview for '%s'", original_name)

			preview_path = preview_path if preview_path is not None else path
			increment += 1

			upload_id = self.db.execute(
				'INSERT INTO uploads SET page_id = %s, increment = %s, '
				'mime = %s, path = %s, preview_path = %s, original_name = %s',
				origin, increment, content_type, os.path.basename(path),
				preview_path, original_name)

			self.db.execute(
				'UPDATE pages SET upload_increment = upload_increment + 1 '
				'WHERE id = %s', origin)

			uploads.append(self.db.get(
				'SELECT * FROM uploads WHERE id = %s', upload_id))

		return uploads

	def delete_upload(self, upload_id):
		upload = self.db.get(
			'SELECT * FROM uploads WHERE id = %s', upload_id)

		if not delete_uploaded_file(self._base_path, upload):
			logging.error('Missing file not removed')

		self.db.execute(
			'DELETE FROM uploads WHERE id = %s', upload_id)

		return True

	def _generate_name(self, file_name):
		f, ext = os.path.splitext(file_name)
		name = random_string(self.settings['upload_name_length']) + ext

		if self._file_exists(name):
			self._generate_name(file_name)
			return

		return name

	def _file_exists(self, new_name):
		check_path = os.path.join(
			self.settings['static_path'], self.settings['upload_path'], new_name)

		if os.path.exists(check_path):
			return True

		return False

	def _upload_increment(self, page_id):
		return self.db.get(
			'SELECT upload_increment FROM pages WHERE id = %s',
			page_id).upload_increment

	@property
	def _base_path(self):
		return os.path.join(
			self.settings['static_path'], self.settings['upload_path'])


class ProcessingMixin(object):
	def process_html(self, origin, html):
		uploads = self.db.query(
			'SELECT increment, path FROM uploads WHERE page_id = %s '
			'ORDER BY created ASC', origin)

		if uploads is None:
			return html

		html = tornado.template.Template(html).generate(
			static_url=self.static_url,
			upload_url=self.upload_url,
			#**{'_%s' % u.increment: self.upload_url(u.path) for u in uploads})
			**{})

		return html


class MessagesMixin(object):
	_NAME = 'message'
	_TYPES = {
		10: 'debug',
		20: 'info',
		25: 'success',
		30: 'warning',
		40: 'error'
	}

	def add_message(self, message, type=25):
		self.set_secure_cookie(self._NAME,
			tornado.escape.json_encode(dict(
				type=self._TYPES[type],
				message=message
			)))

	def get_message(self):
		cookie = self.get_secure_cookie(self._NAME)
		if cookie is None:
			return None

		self.clear_cookie(self._NAME)
		return tornado.escape.json_decode(cookie)
